/********************************** (C) COPYRIGHT
*******************************
* File Name          : Debug.C
* Author             : WCH
* Version            : V1.0
* Date               : 2017/01/20
* Description        : CH554 DEBUG Interface
                     CH554主频修改、延时函数定义
                     串口0和串口1初始化
                     串口0和串口1的收发子函数
                     看门狗初始化
*******************************************************************************/
#include "System.h"

xdata uint16_t FTimer1Count;

/*******************************************************************************
* Function Name  : SystemInit( )
* Description    : CH554时钟选择和配置函数,默认使用Fsys 6MHz，FREQ_SYS可以通过
                   CLOCK_CFG配置得到，公式如下：
                   Fsys = (Fosc * 4/(CLOCK_CFG &
MASK_SYS_CK_SEL);具体时钟需要自己配置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void SystemInit(SysFreqType SysFreq) {
  irq_enable(false);
  safe_enter();  // 进入安全模式
  if (SysFreq == sfExt) {
    SetBit(CLOCK_CFG, bOSC_EN_XT);  // 使能外部晶振
    DelayMs(10);
    safe_enter();  // 进入安全模式
    ResetBit(CLOCK_CFG, bOSC_EN_INT);  // 关闭内部晶振
  } else {
    ResetBit(CLOCK_CFG, MASK_SYS_CK_SEL);
    SetBit(CLOCK_CFG, SysFreq);
  }
  safe_exit();  // 退出安全模式
  DelayMs(20); /* 修改主频等待内部晶振稳定,必加 */
}

/*******************************************************************************
 * Function Name  : DelayUs(UNIT16 n)
 * Description    : us延时函数
 * Input          : UNIT16 n
 * Output         : None
 * Return         : None
 *******************************************************************************/
#ifndef USE_HW_MS_DELAY
#ifndef USE_HW_TIMER_MS_DELAY
void DelayUs(uint16_t n) {  // 以uS为单位延时
  // uint8_t p1usCount = T1US_COUNT - 2;
  // while (n){
  //   while (p1usCount--);
  //   p1usCount = T1US_COUNT - 2;
  //   --n;
  // }
  while (--n) {
    ++SAFE_MOD;
    ++SAFE_MOD;
    ++SAFE_MOD;
  }
}
#endif
#endif

/*******************************************************************************
 * Function Name  : DelayMs(UNIT16 n)
 * Description    : ms延时函数
 * Input          : UNIT16 n
 * Output         : None
 * Return         : None
 *******************************************************************************/
void DelayMs(uint16_t n) {  // 以mS为单位延时
#ifdef USE_HW_MS_DELAY
  n = (uint16_t)(n * 1.005);
#endif
  while (n) {
    n--;
    #ifdef USE_HW_MS_DELAY
        while ((TKEY_CTRL & bTKC_IF) == 0);
        while (TKEY_CTRL & bTKC_IF);
    #else
    #ifdef USE_HW_TIMER_MS_DELAY
        while (TMR2CNT >= 100);
    #else
        DelayUs(1000);
    #endif
    #endif
  }
}

void Timer0Reload(uint8_t ATLCnt, uint8_t ATHCnt) { //向下计数
  TL0 = ATLCnt;
  TH0 = ATHCnt;
}

void Timer0Init(TimerMode ATimerMode, TimerClk ATimerClk) {
  SetBit(TMOD, ATimerMode & MASK_T0_MOD); //模式0-3
  ResetBit(TMOD, bT0_CT); //计时器方式
  ResetBit(TMOD, bT0_GATE); //定时器启动与int0无关
  if (ATimerClk == tnclkFsysDiv12) {
    ResetBit(T2MOD, bT0_CLK);
  } else if (ATimerClk == tnclkFsysDiv4) {
    SetBit(T2MOD, bT0_CLK);
    ResetBit(T2MOD, bTMR_CLK);
  } else if (ATimerClk == tnclkFsys) {
    SetBit(T2MOD, bT0_CLK);
    SetBit(T2MOD, bTMR_CLK);
  }
  // slow = fsys/12; fast1 = fsys/4; fast2 = fsys
}

xdata uint16_t FTimer0Count;

// Timer1 can use for uart baudrate generation
void Timer1Init(TimerMode ATimerMode, TimerClk ATimerClk) {
  SetBit(TMOD, (ATimerMode << 4) & MASK_T1_MOD); //模式0-3
  ResetBit(TMOD, bT1_CT);
  ResetBit(TMOD, bT1_GATE);
  if (ATimerClk == tnclkFsysDiv12) {
    ResetBit(T2MOD, bT1_CLK);
  } else if (ATimerClk == tnclkFsysDiv4) {
    SetBit(T2MOD, bT1_CLK);
    ResetBit(T2MOD, bTMR_CLK);
  } else if (ATimerClk == tnclkFsys) {
    SetBit(T2MOD, bT1_CLK);
    SetBit(T2MOD, bTMR_CLK);
  }
  // slow = fsys/12; fast1 = fsys/4; fast2 = fsys
}

uint16_t TimerxTick(TimerClk ATimerClk, uint16_t ATimeoutUs) {
  if (ATimerClk == tnclkFsysDiv12) {
    return ATimeoutUs * ((Fosc / 12) / 1000000);
  } else if (ATimerClk == tnclkFsysDiv4) {
    return ATimeoutUs * ((Fosc >> 2) / 1000000);
  } else if (ATimerClk == tnclkFsys) {
    return ATimeoutUs * (Fosc / 1000000);
  }
}

void Timer1Reload(uint8_t ATLCnt, uint8_t ATHCnt){
  TL1 = ATLCnt;
  TH1 = ATHCnt;
}

uint32_t Uart0Init(UartMode AUartMode, UartBaudClk AUartBaudClk, uint32_t ABaudRate) {
  ResetBit(SCON, MASK_UART0_MOD);
  SetBit(SCON, AUartMode << 6); //sm0, sm1
  if (AUartMode == umM1_8BitsT1T2 || AUartMode == umM3_9BitsT1T2) {
    SM2 = 0;
    if (AUartBaudClk == ubcTimer2) {
      RCLK = 1;
      TCLK = 1;
      timer2_enable(true);
    } else { //(AUartBaudClk == ubcTimer1) and default
      uint32_t thCount = 256 - ((Fosc >> 4) / ABaudRate); // 如果更改主频，注意x的值不要溢出
      RCLK = 0;
      TCLK = 0;
      SetBit(PCON, SMOD); //fast mode
      Timer1Init(tm8bitsAutoload, tnclkFsys);
      Timer1Reload(thCount, thCount);
      timer1_enable(true);
    } 
  } else if (AUartMode == umM2_9BitsFsysDiv128Div32) {
    SM2 = 0;
    if (AUartBaudClk == ubcFsysDiv128) {
      ResetBit(PCON, SMOD); // slow mode
      ABaudRate = (uint32_t)(Fsys / 128);
    } else { //ubcFsysDiv32
      SetBit(PCON, SMOD);
      ABaudRate = (uint32_t)(Fsys / 32);
    }
  } else { //ubcFsysDiv12
    SM2 = 0;
    ABaudRate = (uint32_t)(Fsys / 12);
  }
  TI = 0;
  uart0_recv_enable(true);
  return ABaudRate;
}

/*******************************************************************************
 * Function Name  : Uart0RcvByte()
 * Description    : Uart0接收一个字节
 * Input          : None
 * Output         : None
 * Return         : SBUF
 *******************************************************************************/
uint8_t Uart0RcvByte(void) {
  while (RI == 0);  // 查询接收，中断方式可不用
  RI = 0;
  return SBUF;
}

/*******************************************************************************
 * Function Name  : Uart0SendByte(uint8_t SendDat)
 * Description    : Uart0发送一个字节
 * Input          : uint8_t SendDat；要发送的数据
 * Output         : None
 * Return         : None
 *******************************************************************************/
void Uart0SendByte(uint8_t SendDat) {
  SBUF = SendDat;  // 查询发送，中断方式可不用下面2条语句,但发送前需TI=0
  while (TI == 0);
  TI = 0;
}

/*******************************************************************************
 * Function Name  : Uart1Init(uint32_t ABuadRate)
 * Description    : CH554串口1初始化
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void Uart1Init(uint32_t ABuadRate) {
  U1SM0 = 0;   // UART1选择8位数据位
  U1SMOD = 1;  // 快速模式
  U1REN = 1;   // 使能接收
  SBAUD1 = 0 - Fosc / 16 / ABuadRate;
}

/*******************************************************************************
 * Function Name  : Uart1RcvByte()
 * Description    : CH554UART1接收一个字节
 * Input          : None
 * Output         : None
 * Return         : SBUF
 *******************************************************************************/
uint8_t Uart1RcvByte(void) {
  while (U1RI == 0);  // 查询接收，中断方式可不用
  U1RI = 0;
  return SBUF1;
}

/*******************************************************************************
 * Function Name  : Uart1SendByte(uint8_t SendDat)
 * Description    : CH554UART1发送一个字节
 * Input          : uint8_t SendDat；要发送的数据
 * Output         : None
 * Return         : None
 *******************************************************************************/
void Uart1SendByte(uint8_t SendDat) {
  SBUF1 = SendDat;  // 查询发送，中断方式可不用下面2条语句,但发送前需TI=0
  while (U1TI == 0);
  U1TI = 1;
}

/*******************************************************************************
* Function Name  : WdtModeSelect(uint8_t mode)
* Description    : CH554看门狗模式选择
* Input          : uint8_t mode
                   0  timer
                   1  watchDog
* Output         : None
* Return         : None
*******************************************************************************/
void WdtModeSelect(bool enable) {
  SAFE_MOD = 0x55;
  SAFE_MOD = 0xaa;  // 进入安全模式
  if (enable)
    SetBit(GLOBAL_CFG, bWDOG_EN);    // 启动看门狗复位
  else
    ResetBit(GLOBAL_CFG, bWDOG_EN);  // 启动看门狗仅仅作为定时器
  SAFE_MOD = 0x00;            // 退出安全模式
  WDOG_COUNT = 0;             // 看门狗赋初值
}

#ifndef DEBUG_OFF
void Uart0Printf(char* str) {
  uint16_t timeout = 0;
  while (*str) {
    SBUF = *str;  // 查询发送，中断方式可不用下面2条语句,但发送前需TI=0
    timeout = 0;
    str++;
    while (TI == 0){
      if(timeout++ > 1000) break;
    }
    TI = 0;
  }
}
#endif
